package com.gzstv.dlnasdk.server;

import android.util.Log;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class LocalContentServer implements Runnable {

    private static final String TAG = "LocalContentServer";
    private static final int PORT = 8080; // You can choose any available port

    private ServerSocket serverSocket;
    private ExecutorService executorService;
    private File contentFile;

    public LocalContentServer() {
        executorService = Executors.newCachedThreadPool();
    }

    public String startServer(File file) throws IOException {
        this.contentFile = file;
        serverSocket = new ServerSocket(PORT);
        executorService.submit(this);
        String ipAddress = getLocalIpAddress();
        if (ipAddress == null) {
            throw new IOException("Could not get local IP address.");
        }
        return "http://" + ipAddress + ":" + PORT + "/" + file.getName();
    }

    public void stopServer() {
        if (serverSocket != null && !serverSocket.isClosed()) {
            try {
                serverSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "Error closing server socket", e);
            }
        }
        if (executorService != null) {
            executorService.shutdownNow();
        }
    }

    @Override
    public void run() {
        Log.d(TAG, "LocalContentServer started on port " + PORT);
        while (!Thread.currentThread().isInterrupted()) {
            try {
                Socket clientSocket = serverSocket.accept();
                executorService.submit(new ClientHandler(clientSocket, contentFile));
            } catch (IOException e) {
                if (!serverSocket.isClosed()) {
                    Log.e(TAG, "Error accepting client connection", e);
                }
                break;
            }
        }
        Log.d(TAG, "LocalContentServer stopped.");
    }

    private String getLocalIpAddress() {
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
                NetworkInterface intf = en.nextElement();
                for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
                    InetAddress inetAddress = enumIpAddr.nextElement();
                    if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress() && inetAddress.isSiteLocalAddress()) {
                        return inetAddress.getHostAddress();
                    }
                }
            }
        } catch (SocketException ex) {
            Log.e(TAG, ex.toString());
        }
        return null;
    }

    private static class ClientHandler implements Runnable {
        private Socket clientSocket;
        private File fileToServe;

        public ClientHandler(Socket clientSocket, File fileToServe) {
            this.clientSocket = clientSocket;
            this.fileToServe = fileToServe;
        }

        @Override
        public void run() {
            try (InputStream inputStream = clientSocket.getInputStream();
                 OutputStream outputStream = clientSocket.getOutputStream()) {

                // Read HTTP request (simplified)
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                String line;
                while ((line = reader.readLine()) != null && !line.isEmpty()) {
                    // Just read the request lines, not parsing them fully for this simple server
                    Log.d(TAG, "Request: " + line);
                }

                if (fileToServe != null && fileToServe.exists() && fileToServe.isFile()) {
                    long fileLength = fileToServe.length();
                    String contentType = URLConnection.guessContentTypeFromName(fileToServe.getName());
                    if (contentType == null) {
                        contentType = "application/octet-stream"; // Default if type cannot be guessed
                    }

                    // Send HTTP response headers
                    outputStream.write(("HTTP/1.1 200 OK\r\n" +
                            "Content-Type: " + contentType + "\r\n" +
                            "Content-Length: " + fileLength + "\r\n" +
                            "Connection: close\r\n" +
                            "\r\n").getBytes());

                    // Send file content
                    try (FileInputStream fileInputStream = new FileInputStream(fileToServe)) {
                        byte[] buffer = new byte[4096];
                        int bytesRead;
                        while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                            outputStream.write(buffer, 0, bytesRead);
                        }
                    }
                    Log.d(TAG, "Served file: " + fileToServe.getName());
                } else {
                    // File not found or not specified
                    outputStream.write(("HTTP/1.1 404 Not Found\r\n" +
                            "Content-Type: text/plain\r\n" +
                            "Content-Length: 9\r\n" +
                            "Connection: close\r\n" +
                            "\r\n" +
                            "Not Found").getBytes());
                    Log.w(TAG, "File not found or not specified: " + (fileToServe != null ? fileToServe.getAbsolutePath() : "null"));
                }

            } catch (IOException e) {
                Log.e(TAG, "Error handling client connection", e);
            } finally {
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    Log.e(TAG, "Error closing client socket", e);
                }
            }
        }
    }
}
